#include <rtthread.h>
#include <rtdevice.h>
#include "cpu_port.h"
#include "device.h"
#include "board_config.h"
#include <spi-bit-ops.h>

struct at32_soft_spi_config
{
    rt_uint8_t clk;
    rt_uint8_t miso;
    rt_uint8_t mosi;
    const char *bus_name;
};
/* at32 sspi dirver class */
struct at32_sspi
{

    struct rt_spi_bit_obj spi_bus;
    struct rt_spi_configuration config;
    struct rt_spi_bit_ops ops;
};

#ifdef BSP_USING_SSPI
#define SSPI_BUS_CONFIG            \
    {                              \
        .clk = 109,                \
        .miso = 108,               \
        .mosi = 107,               \
        .bus_name = "sspi",        \
    }
#endif

static const struct at32_soft_spi_config soft_spi_config[] =
    {
#ifdef BSP_USING_SSPI
        SSPI_BUS_CONFIG,
#endif
};

static struct at32_sspi sspi_obj[sizeof(soft_spi_config) / sizeof(soft_spi_config[0])];

static void at32_sspi_gpio_init(struct at32_sspi *sspi)
{
    struct at32_soft_spi_config *cfg = (struct at32_soft_spi_config *)sspi->ops.data;

    rt_pin_mode(cfg->clk, PIN_MODE_OUTPUT);
    rt_pin_mode(cfg->mosi, PIN_MODE_OUTPUT);
    rt_pin_mode(cfg->miso, PIN_MODE_INPUT);

    // rt_pin_write(cfg->clk, PIN_LOW);
    // rt_pin_write(cfg->mosi, PIN_LOW);
    // rt_pin_write(cfg->miso, PIN_LOW);
}

static void sspi_tog_sclk(void *data)
{
    struct at32_soft_spi_config *cfg = (struct at32_soft_spi_config *)data;

    if (rt_pin_read(cfg->clk) == SET)
    {
        rt_pin_write(cfg->clk, PIN_LOW);
    }
    else
    {
        rt_pin_write(cfg->clk, PIN_HIGH);
    }
}
static void sspi_set_sclk(void *data, rt_int32_t state)
{
    struct at32_soft_spi_config *cfg = (struct at32_soft_spi_config *)data;
    rt_pin_write(cfg->clk, state);
    // if (state)
    // {
    //     rt_pin_write(cfg->clk, PIN_HIGH);
    // }
    // else
    // {
    //     rt_pin_write(cfg->clk, PIN_LOW);
    // }
}

static void sspi_set_mosi(void *data, rt_int32_t state)
{
    struct at32_soft_spi_config *cfg = (struct at32_soft_spi_config *)data;
    rt_pin_write(cfg->mosi, state);
    // if (state)
    // {
    //     rt_pin_write(cfg->mosi, PIN_HIGH);
    // }
    // else
    // {
    //     rt_pin_write(cfg->mosi, PIN_LOW);
    // }
}

static void sspi_set_miso(void *data, rt_int32_t state)
{
    struct at32_soft_spi_config *cfg = (struct at32_soft_spi_config *)data;
    rt_pin_write(cfg->miso, state);
    // if (state)
    // {
    //     rt_pin_write(cfg->miso, PIN_HIGH);
    // }
    // else
    // {
    //     rt_pin_write(cfg->miso, PIN_LOW);
    // }
}

static rt_int32_t sspi_get_sclk(void *data)
{
    struct at32_soft_spi_config *cfg = (struct at32_soft_spi_config *)data;
    return rt_pin_read(cfg->miso);
}

static rt_int32_t sspi_get_mosi(void *data)
{
    struct at32_soft_spi_config *cfg = (struct at32_soft_spi_config *)data;
    return rt_pin_read(cfg->mosi);
}

static rt_int32_t sspi_get_miso(void *data)
{
    struct at32_soft_spi_config *cfg = (struct at32_soft_spi_config *)data;
    return rt_pin_read(cfg->miso);
}

static void sspi_dir_mosi(void *data, rt_int32_t state)
{
    struct at32_soft_spi_config *cfg = (struct at32_soft_spi_config *)data;
    if (state)
    {
        rt_pin_mode(cfg->mosi, PIN_MODE_INPUT_PULLUP);
    }
    else
    {
        rt_pin_mode(cfg->mosi, PIN_MODE_OUTPUT_OD);
    }
}

static void sspi_dir_miso(void *data, rt_int32_t state)
{
    struct at32_soft_spi_config *cfg = (struct at32_soft_spi_config *)data;
    if (state)
    {
        rt_pin_mode(cfg->miso, PIN_MODE_INPUT_PULLUP);
    }
    else
    {
        rt_pin_mode(cfg->miso, PIN_MODE_OUTPUT_OD);
    }
}

static void sspi_udelay(rt_uint32_t us)
{
//    rt_uint32_t ticks;
//    rt_uint32_t told, tnow, tcnt = 0;
//    rt_uint32_t reload = SysTick->LOAD;
//
//    ticks = us * reload / (1000000 / RT_TICK_PER_SECOND);
//    told = SysTick->VAL;
//    while (1)
//    {
//        tnow = SysTick->VAL;
//        if (tnow != told)
//        {
//            if (tnow < told)
//            {
//                tcnt += told - tnow;
//            }
//            else
//            {
//                tcnt += reload - tnow + told;
//            }
//            told = tnow;
//            if (tcnt >= ticks)
//            {
//                break;
//            }
//        }
//    }

    DEVICE_DELAY_US(us);
}

static struct rt_spi_bit_ops at32_sspi_bit_ops_default =
    {
        .data = RT_NULL,
        .tog_sclk = sspi_tog_sclk,
        .set_sclk = sspi_set_sclk,
        .set_mosi = sspi_set_mosi,
        .set_miso = sspi_set_miso,
        .get_sclk = sspi_get_sclk,
        .get_mosi = sspi_get_mosi,
        .get_miso = sspi_get_miso,
        .dir_mosi = sspi_dir_mosi,
        .dir_miso = sspi_dir_miso,
        .udelay = sspi_udelay,
};

rt_err_t rt_sf_spi_device_attach(const char *bus_name, const char *device_name, rt_base_t pinnum)
{
    RT_ASSERT(bus_name != RT_NULL);
    RT_ASSERT(device_name != RT_NULL);

    rt_err_t result;
    struct rt_spi_device *spi_device;
    rt_base_t cs_pin;


    rt_pin_mode(pinnum, PIN_MODE_OUTPUT);
    //片选线要拉高，我这里电平时反的所以拉低了
    rt_pin_write(pinnum, PIN_LOW);

    /* attach the device to spi bus */
    spi_device = (struct rt_spi_device *)rt_malloc(sizeof(struct rt_spi_device));
    RT_ASSERT(spi_device != RT_NULL);
    cs_pin = (rt_base_t)rt_malloc(sizeof(rt_base_t));
    RT_ASSERT(cs_pin != RT_NULL);
    cs_pin = pinnum;
    result = rt_spi_bus_attach_device(spi_device, device_name, bus_name, (void *)cs_pin);

    RT_ASSERT(result == RT_EOK);

    return result;
}

int rt_soft_spi_init(void)
{
    rt_size_t obj_num = sizeof(sspi_obj) / sizeof(struct at32_sspi);
    rt_err_t result;
    for (int i = 0; i < obj_num; i++)
    {
        sspi_obj[i].ops.data = (void *)&soft_spi_config[i];
        at32_sspi_bit_ops_default.data = (void *)&soft_spi_config[i];
        at32_sspi_gpio_init(&sspi_obj[i]);
        result = rt_spi_bit_add_bus(&(sspi_obj[i].spi_bus), soft_spi_config[i].bus_name, &at32_sspi_bit_ops_default);
        RT_ASSERT(result == RT_EOK);
    }
    return result;
}



INIT_BOARD_EXPORT(rt_soft_spi_init);
